home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
mac
/
files
/
misc
/
hamrtty.arc
/
TTYLNY.ASM
< prev
next >
Wrap
Assembly Source File
|
1980-01-01
|
42KB
|
1,126 lines
PAGE ,132
TITLE TTY - Radio Teletype Communications Program
;
; TTY is a program which allows the IBM Personal
; Computer to be used as a radio teletype terminal.
;
; This program runs under PC-DOS.
; The terminal unit must be connected to COM1.
; The terminal unit must activate the DATA SET READY
; status line to the COM1 port.
;
; See CQ magazine, November 1983, for an explanation of
; this program and how it works on the PC.
;
; Author: Jack Botner, VE3LNY
; BOTNER at TOROLAB
; Date: November 1983
; Made available to IBMARC by VE3LNY.
;
; Operation:
;
; Type 'TTY' from DOS. Select the rtty code and baud rate.
; The program then enters receive mode. To transmit, press
; F5. To send your CWid at the end of a transmission, press
; F6. To return to receive, press F10. To select another
; rtty code/baud rate, or end the program, press F10 again.
; In receive using Murray code, if noise causes a false
; shift, use the F2 key to correct the shift state.
;
; Note that receive errors are common on RTTY, due to noise
; and interference on the signals. This program detects some
; of these errors as "framing" errors. The symbol corresponding
; to ascii code 15 (decimal) is displayed when one or more
; receive errors are detected. This symbol appears like a
; double asterisk and tells you that there are receive errors.
;
;*****************************************************************
; Use of this program is subject to the following conditions:
; 1. That it be distributed to and used by licenced amateur radio
; operators only;
; 2. That it be used for amateur radio purposes only;
; 3. Under no circumstances can this program be sold or otherwise
; used commercially or for profit;
; 4. That the origin and purpose of this program not be removed
; from this source code file.
;*****************************************************************
;
; Macro Definitions
DISPLAY MACRO TEXT
MOV DX,OFFSET TEXT
MOV AH,9 ;Print String DOS function
INT 21H ;call DOS
ENDM
;
LOCATE MACRO
MOV AH,3 ;Read cursor posn BIOS function
XOR BH,BH ;Page 0
INT 10H ;call BIOS
ENDM
;
SETCRS MACRO
MOV AH,2 ;set cursor position BIOS function
XOR BH,BH ;page 0
INT 10H ;call BIOS
ENDM
;
SCROLL MACRO
MOV AH,6 ;Scroll up BIOS function
XOR CX,CX ;begin row,col = 1,1
MOV DH,21 ;end row = 22
MOV DL,79 ;end col = 80
MOV BH,00000111B ;attribute byte
INT 10H ;call BIOS
ENDM
;
; Equates
CR EQU 0DH
LF EQU 0AH
BEL EQU 0EH ;Bell symbol (display)
ERR EQU 0FH ;Error symbol for display
;
STACK SEGMENT PARA STACK 'STACK'
DB 64 DUP ('STACK ')
STACK ENDS
;
SUBTTL TTY Data and Workarea Definitions
;
DATA SEGMENT PARA PUBLIC 'DATA'
CWID DB 'DE URCALL$' ;Your call here for CWid
;
; Communications Parameters Tables for 8250 COM1.
; Table entries correspond to fkey descriptions
; for Fkeys: F1 F2 F3
DLABM DB 00AH,06H,04H ;Divisor Latch most significant byte
DLABL DB 000H,14H,17H ;Divisor latch least significant byte
LCR DB 004H,04H,3EH ;Line control reg. (bits, parity, etc.)
RCODE DB 001H,01H,02H ;1=murray (baudot), 2=ascii code
REQUEST DB 0 ;Which Fkey was selected
;
; Main selection panel
PANEL1 DB 'Teletype Terminal Program',CR,LF,CR,LF,CR,LF
DB 'F1: Murray 45 baud, 5 data bits, 2 stop bits, parity N'
DB CR,LF,CR,LF
DB 'F2: Murray 74 baud, 5 data bits, 2 stop bits, parity N'
DB CR,LF,CR,LF
DB 'F3: Ascii 110 baud, 7 data bits, 2 stop bits, parity S'
DB CR,LF,CR,LF
DB 'F10: END Program$'
;
LIN25 DB 'F2=SHIFT F5=XMIT F6=CWID F10=END$'
ERR1 DB CR,LF,'No communications adapter address in system.'
DB CR,LF,'$'
ERR2 DB CR,LF,'Time-out error on communications adapter.'
DB ' Check your modem/TU',CR,LF,'$'
ERR3 DB CR,LF,'Your display must be configured for 80 column'
DB ' width.',CR,LF,'$'
ERR4 DB 'and press any key to retry (Esc key to end).'
DB CR,LF,'$'
;
RMSG DB 'Receiving...$'
TMSG DB 'Transmitting...$'
;
; Tables for converting Murray to Ascii & back
LTRTAB DB 0,'E',LF,'A SIU',CR,'DRJNFCKTZLWHYPQOBG MXV '
FIGTAB DB 0,'3',LF,'- ',BEL,'87',CR,'$4',27H,',!:(5',22H
DB ')2#6019?& ./; '
;
; bit 0: 0 = char defined, 1 = char not defined
; bit 1: 0 = LTRS, 1 = FIGS
; bit 2: 1 = same code for either shift
; bits 3-7: Murray code for character
; LF
MURRAY DB 10 DUP(80H),22H,80H,80H
; CR SP ! " # $ % &
DB 28H,18 DUP(80H),24H,4DH,51H,54H,49H,80H,5AH
; ' ( ) * + , - . / 0 1 2 3 4
DB 4BH,4FH,52H,80H,80H,4CH,43H,5CH,5DH,56H,57H,53H,41H,4AH
; 5 6 7 8 9 : ; < = > ? @ A B
DB 50H,55H,47H,46H,58H,4EH,5EH,80H,80H,80H,59H,80H,03H,19H
; C D E F G H I J K L M N O P
DB 0EH,09H,01H,0DH,1AH,14H,06H,0BH,0FH,12H,1CH,0CH,18H,16H
; Q R S T U V W X Y Z ╒\σ^_ '
DB 17H,0AH,05H,10H,07H,1EH,13H,1DH,15H,11H,5 DUP(80H),4BH
; a b c d e f g h i j k l m n
DB 03H,19H,0EH,09H,01H,0DH,1AH,14H,06H,0BH,0FH,12H,1CH,0CH
; o p q r s t u v w x y z {]}~
DB 18H,16H,17H,0AH,05H,10H,07H,1EH,13H,1DH,15H,11H,5 DUP(80H)
;
LCRAD DW ? ;8250 LCR address
; CW Speed Factor - larger number
SPEED DW 16000 ; means slower CW speed
CWIDPTR DW ?
;
; Table for generating CWid.
; Each hex byte 'ab' in the table represents the following:
; 1. Turn the Break bit on in the comm adapter
; 2. Wait 'a' units of time
; 3. Turn the Break bit off in the comm adapter
; 4. Wait 'b' units of time.
; When 'b' equals 2, the character is complete.
TABLE DB 'A',11H,32H,00H,00H,00H,00H
DB 'B',31H,11H,11H,12H,00H,00H
DB 'C',31H,11H,31H,12H,00H,00H
DB 'D',31H,11H,12H,00H,00H,00H
DB 'E',12H,00H,00H,00H,00H,00H
DB 'F',11H,11H,31H,12H,00H,00H
DB 'G',31H,31H,12H,00H,00H,00H
DB 'H',11H,11H,11H,12H,00H,00H
DB 'I',11H,12H,00H,00H,00H,00H
DB 'J',11H,31H,31H,32H,00H,00H
DB 'K',31H,11H,32H,00H,00H,00H
DB 'L',11H,31H,11H,12H,00H,00H
DB 'M',31H,32H,00H,00H,00H,00H
DB 'N',31H,12H,00H,00H,00H,00H
DB 'O',31H,31H,32H,00H,00H,00H
DB 'P',11H,31H,31H,12H,00H,00H
DB 'Q',31H,31H,11H,32H,00H,00H
DB 'R',11H,31H,12H,00H,00H,00H
DB 'S',11H,11H,12H,00H,00H,00H
DB 'T',32H,00H,00H,00H,00H,00H
DB 'U',11H,11H,32H,00H,00H,00H
DB 'V',11H,11H,11H,32H,00H,00H
DB 'W',11H,31H,32H,00H,00H,00H
DB 'X',31H,11H,11H,32H,00H,00H
DB 'Y',31H,11H,31H,32H,00H,00H
DB 'Z',31H,31H,11H,12H,00H,00H
DB '1',11H,31H,31H,31H,32H,00H
DB '2',11H,11H,31H,31H,32H,00H
DB '3',11H,11H,11H,31H,32H,00H
DB '4',11H,11H,11H,11H,32H,00H
DB '5',11H,11H,11H,11H,12H,00H
DB '6',31H,11H,11H,11H,12H,00H
DB '7',31H,31H,11H,11H,12H,00H
DB '8',31H,31H,31H,11H,12H,00H
DB '9',31H,31H,31H,31H,12H,00H
DB '0',31H,31H,31H,31H,32H,00H
DB '.',11H,31H,11H,31H,11H,32H
DB ',',31H,31H,11H,11H,31H,32H
DB '-',31H,11H,11H,11H,32H,00H
DB '?',11H,11H,31H,31H,11H,12H
DB '/',31H,11H,11H,31H,12H,00H
DB 0FFH ;Mark end of table
;
SW1 DB 0 ;Program switches
SHON EQU 10000000B ;Shift state = FIGS
TRON EQU 01000000B ;In transmit state
AERRON EQU 00100000B ;Ascii error flag
OVRUN EQU 00010000B ;Overrun error occurred bit
FERON EQU 00001000B ;Last char had framing error bit
ASCII EQU 00000001B ;0=Murray, 1=ASCII
;
SW2 DB 0
CRON EQU 10000000B ;Last char was CR
LFON EQU 01000000B ;Last char was LF
DATA ENDS
;
SUBTTL TTY Code Segment: Mainline
;
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE,DS:DATA,SS:STACK
TTY PROC FAR
PUSH DS ;Establish conditions for
XOR AX,AX ; FAR return to DOS at
PUSH AX ; end of program.
MOV AX,DATA
MOV DS,AX
MOV ES,AX ;ES=DS
JMP START
;
; COM1 receive interrupt routine workarea
COMADDR DW ? ;8250 Async Adapter Address
ADBUF DB 32 DUP (?) ;Receive buffer: data
ERBUF DB 32 DUP (?) ;Receive buffer: status codes
INPTR DB 0 ;Insert byte count
OUTPTR DB 0 ;Extract byte count
ADLEN DB 32 ;Buffer length
ADCNT DB 0 ;Byte count
;
START: CLD
; Make sure display configured for 80 columns
MOV AH,15 ;Current video state BIOS function
INT 10H ;call BIOS
CMP AH,80 ;Width = 80?
JE IA100
DISPLAY ERR3 ;Invalid display config.
JMP PGMEXIT
;
; The ACA address is taken from the first COM adapter addresses
; in the ROM BIOS Data Area, located at segment address 40H.
; The COM adapter address is extracted, and validated to make
; sure the adapter is actually installed.
IA100: PUSH ES
MOV AX,40H
MOV ES,AX ;ROM BIOS Data Area Segment
MOV AX,WORD PTR ES:0 ;Get RS232 Base Address
POP ES
CMP AX,0
JNE IA300
DISPLAY ERR1 ;Invalid adapter specification
JMP PGMEXIT
;
IA300: MOV COMADDR,AX ;Save RS232 Adapter Address
;
; Initialize Communications Environment
;
; Initialize Modem Control Register with DTR flag
MOV DX,COMADDR ;Reload adapter address
ADD DX,4 ;Address Modem Control Register (3FC)
MOV AL,00000001B ;Turn DTR flag on, all others off
OUT DX,AL ;Write MCR register
;
; Receive Modem Status Register from adapter
IA500: MOV CX,22 ;Establish time-out count
MOV DX,COMADDR ;Reload adapter address
ADD DX,6 ;Modem Status Register Address (3FE)
;
IC100: IN AL,DX ;Read Modem Status Register
TEST AL,00100000B ;Test Data Set Ready flag
JZ IC300 ;DSR off - process error
JMP IE100 ;DSR is on - continue
;
IC300: CALL PAUSE ;Retry CX times before giving up,
LOOP IC100 ; waiting PAUSE between retries
;
; Process time-out error by giving user chance to try again
DISPLAY ERR2 ;State error
DISPLAY ERR4 ;State action
; Get response
MOV AH,0CH ;Clr kybd DOS req
MOV AL,7 ;Then direct console input req
INT 21H ;Call DOS
CMP AL,0 ;Returned keystroke
JNE ID100 ;Not extended ASCII
; Discard extended ascii code
MOV AH,7 ;Direct console input req
INT 21H ;Call DOS
JMP IA500 ;Retry test for DSR
;
ID100: CMP AL,27 ;ESCape key?
JE ID300
JMP IA500 ;Retry test for DSR
ID300: JMP PGMEXIT ;That's all, folks
;
; Establish 0C interrupt handling routine vector.
IE100: PUSH DS
MOV AH,25H ;Set Interrupt Vector DOS function
MOV AL,0CH ;Interrupt type
MOV CX,CS
MOV DS,CX
MOV DX,OFFSET INT0C ;ENTRY_0C
INT 21H ;Call DOS
POP DS
;
; Enable IRQ4 interrupt on 8259 interrupt controller
IN AL,21H ;Read IMR
AND AL,11101111B ;Turn off IRQ4 bit to enable interrupt
OUT 21H,AL ;Write OCW1 (IMR)
;
; Enter here to re-set communications parameters
;
; Display TTY Initial Selection Panel
INITIALIZE:
CALL CLEAR ;Clear the screen
MOV DH,3 ;Row=4
XOR DL,DL ;Col=1
SETCRS ;Set cursor address to locate panel
;
DISPLAY PANEL1 ;Display selection panel
;
IG100: MOV AH,8 ;Console input DOS req
INT 21H ;Call DOS
CMP AL,0 ;0=extended ascii code returned
JZ IG300 ;Look for F1-F10
JMP IG100 ;Pressed wrong key
;
IG300: MOV AH,8 ;Console input DOS req
INT 21H ;Call DOS
CMP AL,59 ;F1
JE IG500
CMP AL,60 ;F2
JE IG500
CMP AL,61 ;F3
JE IG500
CMP AL,68 ;F10
JE IG500
JMP IG100
;
IG500: PUSH AX
CALL CLEAR ;Clear the screen
XOR DX,DX ;Row 1, col 1
SETCRS ;Set cursor position
POP AX
;
CMP AL,68 ;F10?
JNE IH100 ;No, select baud etc.
JMP END_RUN ;Run complete
;
IH100: SUB AL,58 ;Make number relative to 0
MOV REQUEST,AL ;Save fkey number
SUB BX,BX
MOV BL,AL ;Create index register for
DEC BX ; table lookup
;
; Write 1 into Divisor Latch Access Bit of Line Control Register
; to allow access to Divisor Latches (Baud Rate Generator).
MOV DX,COMADDR ;Load adapter address
ADD DX,3 ;Point to 8250 control register (3FB)
MOV AL,80H
OUT DX,AL ;Set DLAB=1 (divisor latch access bit)
;
; Write high-order byte of baud rate divisor to Divisor Latch
MOV DX,COMADDR ;Reload adapter address
INC DX ;Divisor Latch Most Sig. Bits (3F9)
MOV AL,DLABM╒BXσ ;Baud rate
OUT DX,AL ;Set baud rate Most Significant Bits
;
; Write low-order byte of baud rate divisor to Divisor Latch
DEC DX ;Divisor Latch Least Sig. Bits (3F8)
MOV AL,DLABL╒BXσ ;Baud rate
OUT DX,AL ;Set Baud Rate Least Significant bits
;
; Write Line Control Register to set Data Bits, Stop Bits, Parity,
; and reset Divisor Latch Access Bit.
ADD DX,3 ;Point to 8250 control reg. (3FB)
MOV AL,LCR╒BXσ ;Set Parity, Stop Bits, Word Lenth
OUT DX,AL ;Send Line Control Register Data
;
; Write Interrupt Enable Register to enable 8250 interrupt.
; Update Modem Control Register to enable interrupts
CALL ENAINT ;Enable interrupt for receive
;
; Get code selection and build info lines
AND SW1,0FFH-ASCII ;Indicate Murray mode
MOV AL,RCODE╒BXσ
CMP AL,02
JNE II100
OR SW1,ASCII ;Indicate ASCII mode
;
; Display Fkey description line 25
II100: MOV DH,24 ;Row 25
XOR DL,DL ;Col 1
SETCRS
DISPLAY LIN25
;
XOR DX,DX ;Row,col = 1,1
SETCRS
AND SW1,0FFH-TRON-SHON-FERON
;
; Scan keyboard for requests
;
READ_KEYBD:
MOV AH,0BH ;Check Keyboard Status DOS code
INT 21H ;Invoke DOS
CMP AL,0 ;00=no character available
JNE MA100
JMP MF400
;
MA100: MOV AH,8 ;Keyboard Input DOS code
INT 21H ;Call DOS
CMP AL,0 ;If AL=0 then char is extended ASCII code
JE MB100 ;Go read second character
TEST SW1,TRON ;If receive mode, ignore character typed
JZ MA500 ; on keyboard and go poll adapter
JMP SEND_ADAPTER
MA500: JMP READ_ADAPTER
;
; Process Extended ASCII code for function key requests.
MB100: MOV AH,8 ;Keyboard Input again
INT 21H ;Invoke DOS
CMP AL,59
JB MB500 ;Check for F1-F10 range
CMP AL,68
JNA MC300
;
MB500: TEST SW1,TRON
JNZ MC100 ;In receive mode, go scan ACA
JMP READ_ADAPTER ; for received character.
MC100: JMP READ_KEYBD
;
MC300: SUB AL,58 ;F1-F10 selected.
;
CMP AL,2 ;Check for F2 key (Toggle Shift)
JNE MD300
TEST SW1,ASCII ;Does not apply to ASCII mode
JNZ MC500
TEST SW1,TRON ;Allow in receive mode only
JZ MC700
MC500: JMP MF200 ;Sound alarm and continue
;
MC700: TEST SW1,SHON ;Process toggle shift
JZ MD100
AND SW1,0FFH-SHON ;Turn the switch off
JMP MF400
MD100: OR SW1,SHON ;Turn the switch on
JMP MF400
;
MD300: CMP AL,5 ;Check for F5 key (transmit request)
JNE ME100
TEST SW1,TRON ;Allow in receive mode only
JZ MD500
JMP MF200 ;Sound alarm and continue
;
MD500: AND SW1,0FFH-SHON ;Reset to LTRS shift
OR SW1,TRON ;Set transmit mode
MOV DX,OFFSET TMSG
CALL DISPLAY_MESSAGE
CALL DISINT ;Disable 8250 adapter interrupts
;
CALL RTSON ;Turn on request-to-send signal
JMP MF400
;
ME100: CMP AL,6 ;Check for F6 key (send CW ID)
JNE ME400
TEST SW1,TRON
JNZ ME300 ;Invalid request if in receive mode
JMP MF200 ;Sound alarm and continue
;
ME300: CALL CWID_RTN ;send CW ID
JMP MF400 ;OK
;
ME400: CMP AL,10 ;Check for F10 key (END)
JE ME500
JMP MF200 ;Go sound alarm for bad Fkey
;
ME500: TEST SW1,TRON ;In transmit mode?
JNZ ME700
JMP MF100
;
ME700: AND SW1,0FFH-TRON ;Return to receive mode here
MOV DX,OFFSET RMSG
CALL DISPLAY_MESSAGE
;
CALL ENAINT ;Enable 8250 adapter interrupts
CALL RTSOFF ;Turn off request-to-send signal
JMP MF400 ;Done with this request
;
MF100: CALL DISINT ;Disable 8250 adapter interrupts
CALL RTSOFF ;Turn off request-to-send signal
JMP INITIALIZE ;Return to main menu
;
MF200 LABEL NEAR
CALL ALARM ;Error or undefined key selected
;
MF400: TEST SW1,TRON ;End of F1-F10 processing
JNZ MG100
JMP READ_ADAPTER ;In receive, continue scanning adapter
MG100: JMP READ_KEYBD
;
; Communicatiins Adapter SEND routine
;
SEND_ADAPTER: ;Char from keyboard in AL
SUB AH,AH
AND AL,01111111B ;Make sure high order bit is zero.
TEST SW1,ASCII
JZ MH100
MOV DL,AL ;ASCII: use character as entered
JMP MH200
;
MH100: MOV SI,AX ;Murray: translate required
MOV DL,MURRAY╒SIσ ;Get Murray equivalent of ASCII
TEST DL,10000000B ;Test for invalid character
JZ MH200
CALL ALARM ;Sound the alarm
JMP MJ500 ;Bypass invalid character
;
MH200: PUSH DX
MOV DL,AL
CALL DISPLAY_CHAR
POP DX
;
TEST SW1,ASCII ;Bypass shift jazz for ASCII
JZ MH400
JMP MI200
MH400: TEST DL,00100000B ;Test shift irrelevant bit
JNZ MI100
TEST DL,01000000B ;Test for shift
JZ MH600
; Char to send is FIGS
TEST SW1,SHON ;What was sent last?
JNZ MI100
MOV AL,1BH ;1B = FIGS
CALL XMIT_CHAR
OR SW1,SHON ;Indicate in FIGS shift now
JMP MI100
;
MH600: TEST SW1,SHON ;char to send is LTRS
JZ MI100
MOV AL,1FH ;1F = LTRS
CALL XMIT_CHAR
AND SW1,0FFH-SHON ;Indicate in LTRS shift now
;
MI100: AND DL,00011111B
; Write char in DL to async adapter
MI200: MOV AL,DL ;Char to send
CALL XMIT_CHAR
;
TEST SW1,ASCII ;Bypass shift jazz for ASCII
JNZ MI500
CMP DL,8 ;If a CR was sent (Murray 08H),
JE MI400 ; then a LF must also be sent
JMP MJ500
;
MI400: MOV DL,2 ;LF = Murray 02H
JMP MJ300
;
MI500: CMP DL,CR ;If CR was sent (ASCII),
JE MJ100 ; then a LF must also be sent
JMP MJ500
;
MJ100: MOV DL,LF
; Write character in DL to ACA
MJ300: MOV AL,DL ;Char to send
CALL XMIT_CHAR
MOV DL,LF ;Send to display too
CALL DISPLAY_CHAR
MJ500: JMP READ_KEYBD
;
; Communications Adapter READ routine
;
READ_ADAPTER:
CMP ADCNT,0 ;See if anything is in the buffer
JA MK100
JMP READ_KEYBD ;Buffer is empty - continue elsewhere
;
; The following statuses (of interest) are possible in ERBUF:
; Bit 3 = FRAMING ERROR Bit 1 = OVERRUN ERROR
MK100: CLI ;no interrupts
SUB BH,BH
MOV BL,OUTPTR
MOV AH,ERBUF╒BXσ ;load status byte
MOV AL,ADBUF╒BXσ ;load data byte
INC BL
CMP BL,ADLEN ;perform maintenance on buffer pointer
JB MK300
SUB BL,BL
MK300: MOV OUTPTR,BL
DEC ADCNT
STI ;Interrupts OK now
;
TEST AH,00000010B ;Overrun error?
JZ MK500
OR SW1,OVRUN ;Indicate overrun error occurred
JMP READ_ADAPTER ;throw away byte
;
MK500: TEST AH,00001000B ;Framing error?
JZ ML200
TEST SW1,FERON ;Was the last character in error too?
JZ ML100
JMP READ_ADAPTER ;Yes, ignore this character (gibberish)
;
ML100: OR SW1,FERON ;No, turn on error indicator
MOV DL,ERR ;Indicate error occurred
JMP MM700
;
ML200: AND SW1,0FFH-FERON ;RESET error switch
TEST SW1,ASCII ;don't translate ASCII, of course
JZ ML700
;
; Validate ASCII character
MOV DL,AL ;check ASCII for obvious errors
CMP DL,1FH
JA ML500
CMP DL,CR ;DL is less than 20H, which might be bad
JE ML500
CMP DL,LF
JE ML500
TEST SW1,AERRON ;was last character in error too?
JZ ML400
JMP READ_ADAPTER
ML400: MOV DL,ERR ;substitute error code
OR SW1,AERRON
JMP MM700
ML500: AND SW1,0FFH-AERRON
JMP MM500
;
; Translate MURRAY code to ASCII
ML700: SUB AH,AH ;AL contains Murray character
AND AL,00011111B ;Make sure high 3 bits are off
MOV BX,AX ; and use as base register
CMP AL,1BH ;FIGS character?
JNE MM100
OR SW1,SHON ;Set status to FIGS
JMP READ_ADAPTER ;Go read another character
;
MM100: CMP AL,1FH ;LTRS character?
JNE MM200
AND SW1,0FFH-SHON ;Set status to LTRS
JMP READ_ADAPTER ;Go read another character
;
MM200: TEST SW1,SHON ;Is it FIGS?
JZ MM400
; Translate FIGS character
MOV DL,FIGTAB╒BXσ
JMP MM500
; Translate LTRS character
MM400: MOV DL,LTRTAB╒BXσ
;
MM500: CMP DL,0 ;BLANK char?
JNE MM700
JMP READ_ADAPTER ;BLANK=no print or carriage movement
;
MM700: CALL DISPLAY_CHAR
JMP READ_KEYBD
;
SUBTTL Restore Communications Environment
END_RUN:
;
; Disable Interrupt Enable Register flag
CALL DISINT
;
; Disable IRQ4 interrupt on 8259 interrupt controller
IN AL,21H ;Read IMR
OR AL,00010000B ;turn on IRQ4 bit to disable interrupt
OUT 21H,AL ;Write OCW1 (IMR)
;
; Clear 0C interrupt handling routine vector.
PUSH DS
MOV AH,25H ;Set Interrupt Vector DOS function
MOV AL,0CH ;Interrupt type
XOR DX,DX ;clear address
MOV DS,DX
INT 21H ;call DOS
POP DS
;
; Write Modem Control Register to clear flags
MOV DX,COMADDR ;Load adapter address
ADD DX,4 ;Address modem control register (3FC)
MOV AL,0 ;All flags clear
OUT DX,AL ;Write MCR register
;
CALL CLEAR ;Clear the screen
MOV AH,2 ;Set cursor position BIOS function
XOR DX,DX ;Row,col = 1,1
XOR BH,BH ;Page 0
INT 10H ;Call BIOS
;
PGMEXIT: RET ;Return to DOS
TTY ENDP
;
; Display character in DL routine
;
DISPLAY_CHAR PROC NEAR
PUSH AX
PUSH BX
PUSH CX
CMP DL,CR
JNE SA200
OR SW2,CRON ;Process carrier return
LOCATE
; DH = Row, DL = column of cursor position
XOR DL,DL ;Column = 1
SETCRS ;Set cursor position
JMP SA900
;
SA200: CMP DL,LF
JNE SA400
OR SW2,LFON ;Process line feed
LOCATE
; DH = Row, DL = column of cursor position
INC DH ;Next row
CMP DH,21 ;Past row 22?
JNA SA300
;
PUSH DX
MOV AL,1 ;Scroll 1 line
SCROLL
POP DX
MOV DH,21 ;Row = 22
;
SA300: SETCRS ;Set cursor position
JMP SA900
;
SA400: TEST SW2,CRON ;Process the character
JZ SA600
TEST SW2,LFON ;If preceding CR not accompanied by
JNZ SA600 ; LF, corrective action is necessary
;
LOCATE
; DH = Row, DL = column of cursor position
INC DH ;Next row
CMP DH,21 ;Past row 22?
JNA SA500
;
PUSH DX
MOV AL,1 ;Scroll 1 line
SCROLL
POP DX
MOV DH,21 ;Row = 22
;
SA500: SETCRS ;Set cursor position
;
SA600: MOV AH,9 ;Write char BIOS function
XOR BH,BH ;Page = 0
MOV CX,1 ;Number of characters
MOV AL,DL ;Character
MOV BL,00000111B ;Attribute byte
INT 10H ;Call BIOS
AND SW2,0FFH-CRON-LFON
;
LOCATE ;Read cursor position
; DH = Row, DL = column of cursor position
INC DL ;Next column
CMP DL,79 ;Past end of row?
JNA SA700
;
XOR DL,DL ;Reset to column 1
INC DH ;Next row
CMP DH,21 ;Past row 22?
JNA SA700
;
MOV AL,1 ;Scroll 1 line
SCROLL
MOV DH,21 ;Set cursor to row 22
MOV DL,0 ;Set cursor to column 1
;
SA700: SETCRS ;Set cursor position
;
SA900: POP CX
POP BX
POP AX
RET
DISPLAY_CHAR ENDP
;
; Display a Message routine
;
DISPLAY_MESSAGE PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
LOCATE ;Read cursor position
; DH = Row, DL = column of cursor position
ADD DH,2 ;Add 2 giving target row
CMP DH,21 ;Compare with line 22
JA SC100
JB SC300 ;No scroll required
MOV AL,1 ;Scroll 1 line only
JMP SC200
;
SC100: MOV AL,2 ;Scroll 2 lines
;
SC200: SCROLL ;Scroll up AL lines
;
MOV DH,21 ;Set cursor to row 22
;
SC300: MOV DL,0 ;Set cursor to column 1
SETCRS ;Set cursor position
;
POP DX ;Restore message offset
MOV AH,9 ;Print String DOS function
INT 21H ;Call DOS
;
LOCATE ;Read cursor position
;
ADD DH,2 ;Add 2 giving target row
CMP DH,21 ;Compare with line 22
JA SC400
JB SC600 ;No scroll required
MOV AL,1 ;Scroll 1 line only
JMP SC500
;
SC400: MOV AL,2 ;Scroll 2 lines
;
SC500: SCROLL ;Scroll up AL lines
MOV DH,21 ;set cursor to row 22
;
SC600: MOV DL,0 ;column = 1
SETCRS ;set cursor position
;
SC900: POP CX
POP BX
POP AX
RET
DISPLAY_MESSAGE ENDP
;
; Send CWID Routine
;
CWID_RTN PROC NEAR
PUSH BX
PUSH CX
PUSH DX
PUSH SI
CLD
;
MOV DX,COMADDR ;Point to 8250 Line Control register
ADD DX,3
MOV LCRAD,DX ;Save LCR address
IN AL,DX ;Read current setting of LCR
TEST AL,01000000B ;Is set break bit on?
JZ SF100
AND AL,10111111B ;If break bit is on, turn it off
OUT DX,AL ; and send it back to the adapter
;
SF100: MOV AL,10
CALL CWID_PAUSE ;Pause before sending ID
MOV AX,OFFSET CWID
MOV CWIDPTR,AX
;
SF200: MOV SI,CWIDPTR
MOV AL,BYTE PTR ╒SIσ
CMP AL,'$' ;End of message?
JNE SF300
JMP SG800 ;All done
;
SF300: CMP AL,' ' ;Space?
JNE SF500
;
SF400: MOV AL,2
CALL CWID_PAUSE ;Pause between words
JMP SG500
;
SF500: MOV BX,OFFSET TABLE
; Search for character in table
SF600: MOV AH,BYTE PTR ╒BXσ
CMP AH,0FFH ;End of the table?
JNE SG100
JMP SF400 ;Letter not found in table
;
SG100: CMP AL,AH ;Is this the entry we want?
JE SG200
ADD BX,7 ;Try next entry in table
JMP SF600
;
SG200: INC BX
MOV AL,BYTE PTR ╒BXσ
MOV AH,AL
MOV CL,4
SHR AH,CL ;Extract high-order digit
AND AL,0FH ;Extract low-order digit
;
MOV CX,AX
MOV DX,LCRAD
IN AL,DX ;Read current setting of LCR
OR AL,01000000B ;Turn the break bit on
OUT DX,AL ;Send new LCR register contents
MOV AL,CH ;Table byte (value = 1, 2 or 3)
CALL CWID_PAUSE
;
IN AL,DX ;Read current setting of LCR
AND AL,10111111B ;Turn the break bit off
OUT DX,AL ;Send new LCR register contents
MOV AL,CL ;Table byte (value = 1, 2 or 3)
CALL CWID_PAUSE
;
CMP CL,2 ;2 = character complete
JE SG500
JMP SG200 ;Process next segment of character
;
SG500: INC CWIDPTR ;On to next character
JMP SF200
;
SG800: POP SI
POP DX
POP CX
POP BX
RET
CWID_RTN ENDP
;
CWID_PAUSE PROC NEAR ;relative delay in AL (1-8)
PUSH CX
CMP AL,2 ;2 means end-of-character
JNE SJ100
MOV AL,3 ;Wait 3 after character complete too
;
SJ100: MOV CX,SPEED
SJ200: LOOP SJ200 ;Wait awhile
DEC AL
OR AL,AL ;Test for zero
JNZ SJ100
POP CX
RET
CWID_PAUSE ENDP
;
SUBTTL Enable interrupt on 8250 communications adapter
;
ENAINT PROC NEAR
;
; Write Interrupt Enable Register to enable 8250 interrupt.
MOV DX,COMADDR ;Reload adapter address
INC DX ;Address Interrupt Enable Reg. (3F9)
MOV AL,1 ;Enable Data Available Interrupt
OUT DX,AL ;Send Interrupt Enable Register Data
;
; Update Modem Control Register to enable interrupts
ADD DX,3 ;Address modem control register (3FC)
IN AL,DX ;Present MCR contents
OR AL,00001000B ;Turn ON OUT2 flag
OUT DX,AL ;rewrite MCR register
;
; If an interrupt is pending, the 8250 does not honor the enable
; until it is cleared.
SUB DX,2 ;Interrupt ID. Reg. (3FA)
IN AL,DX ;read Interrupt ID port
TEST AL,00000001B ;0 if interrupt pending
JNZ SM900
SUB DX,2 ;Receiver Buffer Reg. (3F8)
IN AL,DX ;clear pending interrupt - discard byte
SM900: RET
ENAINT ENDP
;
SUBTTL Disable interrupts on 8250 communications adapter
;
DISINT PROC NEAR
;
; Write Interrupt Enable Register to disable 8250 interrupt.
MOV DX,COMADDR ;Reload adapter address
INC DX ;Point to Interrupt Enable Register (3F9
MOV AL,0 ;Disable all interrupts
OUT DX,AL ;Send Interrupt Enable Register Data
;
; Update Modem Control Register to disable interrupts
ADD DX,3 ;Point to modem control register (3FC)
IN AL,DX ;Present MCR contents
AND AL,11110111B ;Turn OUT2 OFF
OUT DX,AL ;Rewrite MCR register
RET
DISINT ENDP
;
SUBTTL Turn ON/OFF Request to Send signal
;
RTSON PROC NEAR
;
; Update Modem Control Register to turn on RTS flag
MOV DX,COMADDR ;Comm Adapter Address
ADD DX,4 ;point to modem control register (3FC)
IN AL,DX ;get current contents of register
OR AL,00000010B ;Turn bit 1 ON (RTS line)
OUT DX,AL ;rewrite MCR register
RET
RTSON ENDP
;
RTSOFF PROC NEAR
;
; Update Modem Control Register to turn off RTS flag
MOV DX,COMADDR ;Comm Adapter Address
ADD DX,4 ;point to modem control register (3FC)
IN AL,DX ;get current contents of register
AND AL,11111101B ;Turn bit 1 OFF (RTS line)
OUT DX,AL ;Rewrite MCR register
RET
RTSOFF ENDP
;
; Send character in AL
XMIT_CHAR PROC NEAR
PUSH DX
PUSH AX ;Save input character
;
XM200: MOV DX,COMADDR ;Load adapter address
ADD DX,5 ;Adress of Line Status Reg. (3FD)
IN AL,DX ;Read LSR
TEST AL,00100000B ;Test TX hold register empty?
JNZ XM400 ;Ready to accept data
JMP XM200 ;Not ready so try again
;
XM400: MOV DX,COMADDR ;Load adapter address THR (3F8)
POP AX ;Restore character
OUT DX,AL ;Write to THR
POP DX
RET
XMIT_CHAR ENDP
;
PAUSE PROC NEAR ;PAUSE routine
PUSH CX
XOR CX,CX
SP100: LOOP SP100
POP CX
RET
PAUSE ENDP
;
CLEAR PROC NEAR ;CLEAR SCREEN Routine
MOV AH,6 ;Scroll up BIOS function
MOV AL,0 ;Clear screen request
XOR CX,CX ;Start row,col = 1,1
MOV DH,24 ;End row = 25
MOV DL,79 ;End col = 80
MOV BH,00000111B ;Attribute byte
INT 10H ;Call BIOS
;
RET
CLEAR ENDP
;
SUBTTL ALARM - Sound the ALARM
;
TIMER EQU 40H
PORT_B EQU 61H ;8255 port B addr
;
ALARM PROC NEAR
PUSH CX
CLD
MOV AL,10110110B ;SEL TIM 2, LSB,MSB,Binary
OUT TIMER+3,AL ;Write the Timer Mode Reg
MOV AX,400H
OUT TIMER+2,AL ;Write Timer 2 cnt - LSB
MOV AL,AH
OUT TIMER+2,AL ;Write Timer 2 cnt - MSB
IN AL,PORT_B ;Get current setting of port
MOV AH,AL ;Save the setting
OR AL,03 ;Turn speaker on
OUT PORT_B,AL
SUB CL,CL ;Set cnt to wait awhile
MOV CH,64
ST100: LOOP ST100 ;Delay before turning off
MOV AL,AH ;Recover value of port
OUT PORT_B,AL
POP CX
RET
ALARM ENDP
;
SUBTTL TTYINTR - Adapter Interrupt 0C Routine
;
INT0C PROC FAR
STI ;Enable interrupts
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
CLD
;
SW100: MOV DX,COMADDR ;Load adapter address
ADD DX,5 ;Address the Line Status Register (3FD)
IN AL,DX ;Read Line Status Register
TEST AL,01H ;Test Data Ready bit
JNZ SW300 ;One means data is available in receive
JMP SW900 ;No data, so quit
;
; The following statuses (of interest) are possible in AL:
; Bit 3 = FRAMING ERROR Bit 1 = OVERRUN ERROR
SW300: MOV CL,AL ;Save status byte in CL
MOV DX,COMADDR ;Get Receive Buffer Register addr (3F8)
IN AL,DX ;Read one byte from adapter
MOV CH,AL ;Save data byte in CH
;
SUB BH,BH
MOV BL,INPTR
MOV ADBUF╒BXσ,CH ;Store data byte in buffer
MOV ERBUF╒BXσ,CL ;Store status byte in buffer
;
INC BL ;Point to next byte in buffers
CMP BL,ADLEN ;Check for wrap-around in buffer
JB SW500
SUB BL,BL ;Reset pointer at wrap-around
SW500: MOV INPTR,BL ;Update pointer
MOV CL,ADCNT
INC CL ;Increment active byte count
CMP CL,ADLEN ;Check for buffer overrun
JNA SW700
MOV CL,1 ;Throw away buffer contents when overrun
SW700: MOV ADCNT,CL
;
SW900: CLI ;Disable interrupts
MOV AL,20H ;Signal end of interrupt to
OUT 20H,AL ; 8259 via OCW2 register
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
IRET
INT0C ENDP
;
CODE ENDS
END TTY